package com.luo.comm.services.mp.sys;


import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.query.MPJQueryWrapper;
import com.luo.comm.dto.SysMenuDto;
import com.luo.comm.entity.sys.SysMenu;
import com.luo.comm.mapper.SysMenuMapper;
import com.luo.comm.utils.mp.MpUtils;
import com.luo.comm.vo.ConditionFields;
import com.luo.comm.vo.ReqBody;
import com.luo.comm.vo.Result;
import lombok.Data;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

/**
 * 封装后的Service，提供save\delete\ update\find\list\findAll 标准方法，如果要用原生的方法，请直接使用UserMapper的相关方法;
 * 标准方法不建议直接修改,便于统一升级和维护。这个里面已经对查询条件、逻辑删除、乐观锁等进行了统一处理。
 * 所有对标准方法的维护，请同步更新到SysUserService，以便于同步到其他的服务中。！！！SysUserService作为升级标准方法的范本！！！
 * 标准方法，提供beforeXxxxx 和afterXxxxx方法，便于自定义部分的修改和扩展。
 * 以save方法为例，内部调用了beforeSave、beforeSaveComm、afterSaveComm、afterSave。以Comm结尾的是公共的方法，要注意保持统一性。
 * save\delete\ update 主要是对格式的统一。
 * find\list\findAll中支持的入参相同，主要包括分页、查部分字段、排序、以及模糊查询和范围查询等特殊字段。
 * 入参示例：{"select":"id,userName,nickName,updatedAt","size":5,"page":1,"between":[{"id":[3,3]}],"orderBy":[{"id":"asc"}]}
 * find\list 是单表查询方法，findAll是联查查询方法
 * public方法是公共方法，仅允许调用。private是私有的。protected 是允许子类继承的方法，可以允许子类重写。
 *
 * @author bill
 * @since 2023-08-27
 */
@Component
@Data
public class SysMenuService {

    @Resource
    SysMenuMapper doMapper;  // 需要处理的主mapper


    /**
     * 单表保存save方法，
     */
    public final <T>  Result save(SysMenu entity) {

        beforeSave(entity);
        beforeSaveComm(entity);
        int count = doMapper.insert(entity);
        return count > 0 ? Result.success(entity) : Result.fail("save失败");
    }

    ;

    protected void beforeSave(SysMenu entity) {
    }

    ;

    private void beforeSaveComm(SysMenu entity) {
        // 调用保存方法前处理过程，进行一些通用字段的处理或通用条件的处理
        MpUtils.beforeSaveCommHandle(entity);
    }


    /**
     * 单表update 单条记录修改的方法。
     * 采用乐观锁更新机制，锁不是version，是updatedAt.精确到豪米。所以每次更新时都要携带updatedAt字段
     */
    public final Result update(SysMenu entity) {
        // updateById 已经全局配置强制要求带updatedAt字段,如果没有或不对则会更新失败
        beforeUpdate(entity);
        beforeUpdateComm(entity);
        int count = doMapper.updateById(entity);
        if (count > 0) {
            afterUpdate(entity); // 更新成功以后，需要处理的个性化方法
        }
        return count > 0 ? Result.success(entity) : Result.fail("update失败");
    }

    ;

    protected void beforeUpdate(SysMenu entity) {
    }

    ;

    protected void afterUpdate(SysMenu entity) {
    }

    ;

    private void beforeUpdateComm(SysMenu entity) {
        // 调用保存方法前处理过程，进行一些通用字段的处理或通用条件的处理
        MpUtils.beforeUpdateCommHandle(entity);
    }

    /**
     * 单表通用delete删除方法.按queryWrapper条件删除。
     * 如果要按id删除，则将id做为条件入参即可
     * 全局配置了会改走软删除，底层实际走的是update方法，例如：UPDATE sys_user SET deleted_at=now() WHERE deleted_at IS NULL AND (id = ?) ORDER BY id ASC
     */
    public final Result delete(ReqBody<SysMenu> reqBody) {

        // 获取ConditionFields，如果实现类未重写beforeFindOpHandle，则默认返回的是一个new ConditionFields()
        ConditionFields conditionFields = beforeFindOpHandle();
        // 转换生成queryWrapper的条件。
        QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>();
        MpUtils.conditionOpCommHandle(reqBody, conditionFields, queryWrapper);

        return Result.success(doMapper.delete(queryWrapper));

    }

    /**
     * 单表查找 find 通用查找单条记录的方法。entity的条件支持eq\like\between\in操作。
     *
     * @param reqBody 传一个SysUser对象到reqBody.setEntity里把整个reqBody传过来处理
     * @return ResultsObj
     */
    public final Result find(ReqBody<SysMenu> reqBody) {
        reqBody.setSize(1);  // find 强制limit为1
        return list(reqBody);
    }

    /**
     * 单表查找 list 通用查找所有记录的方法。entity的条件支持eq\like\between\in操作。
     *
     * @param reqBody 入参
     * @return IPage page
     */
    public final Result list(ReqBody<SysMenu> reqBody) {

        // 获取ConditionFields，如果实现类未重写beforeFindOpHandle，则默认返回的是一个new ConditionFields()
        ConditionFields conditionFields = beforeFindOpHandle();

        // 转换生成queryWrapper的条件。
        QueryWrapper<SysMenu> queryWrapper = new QueryWrapper<>();
        // 分页Ipage
        Page<SysMenu> page = new Page<SysMenu>(reqBody.getPage(), reqBody.getSize());
        MpUtils.conditionOpCommHandle(reqBody, conditionFields, queryWrapper);
        IPage<SysMenu> ipage = doMapper.selectPage(page, queryWrapper);
        return Result.success(ipage);
    }


    /**
     * beforeFindOpHandle ,返回一个条件字段数组集合 ConditionFields
     * 如果子类不重写该方法，则返回默认的 new ConditionFields(),这个里面有默认的初始化数据，比如betweenFieldsArray等。
     */
    protected ConditionFields beforeFindOpHandle() {
        return new ConditionFields();
    }


    /**
     * findAll通用查找所有记录的方法。entity的条件支持eq\like\between\in操作。
     *
     * @param reqBody 入参
     * @return IPage page
     */
    public final Result findAll(ReqBody<SysMenu> reqBody) {

         // 初始化参数

        // 获取ConditionFields，如果实现类未重写beforeFindOpHandle，则默认返回的是一个new ConditionFields()
        ConditionFields conditionFields = beforeFindOpHandle();

        // 转换生成queryWrapper的条件。
        MPJQueryWrapper<SysMenu> mpjQueryWrapper = new MPJQueryWrapper<>();

        // 分页Ipage
        MpUtils.conditionMpjOpCommHandle(reqBody, conditionFields, mpjQueryWrapper);
        IPage<SysMenuDto> iPage = doMapper.selectJoinPage(new Page<SysMenuDto>(reqBody.getPage(), reqBody.getSize()),SysMenuDto.class, mpjQueryWrapper);

        return Result.success(iPage);
    }


}
